---
title: Managing operators
description: Which operators are allowed for which fields, and how they are labeled
hide_table_of_contents: true
---

import { SandpackRQB } from '@site/src/components/SandpackRQB';

Many React Query Builder implementations need to customize operators based on the selected field type. For example, date fields might use "before" as a more intuitive label than the default `"<"` operator. Number fields could display "less than" for the `<` operator, while text fields might exclude comparison operators entirely.

## Field `operators` property

One approach uses the field's `operators` property to specify which operators appear when users select a particular field. However, this method requires defining complete operator lists for each field, potentially creating duplication across fields with similar data types.

<SandpackRQB rqbVersion={7} options={{ editorHeight: 444 }}>

```tsx
import { defaultOperators, Field, QueryBuilder, RuleGroupType } from 'react-querybuilder';
import 'react-querybuilder/dist/query-builder.css';

const fields: Field[] = [
  {
    name: 'name',
    label: 'Name',
    operators: [
      { name: '=', label: 'is' },
      ...defaultOperators.filter(op => ['contains', 'beginsWith', 'endsWith'].includes(op.name)),
    ],
  },
  {
    name: 'birthday',
    label: 'Birthday',
    inputType: 'date',
    operators: [
      { name: '=', label: 'on' },
      { name: '<', label: 'before' },
      { name: '>', label: 'after' },
    ],
  },
  {
    name: 'guitars',
    label: 'Guitars',
    inputType: 'number',
    operators: [
      { name: '=', label: 'equals' },
      { name: '<', label: 'less than' },
      { name: '>', label: 'greater than' },
    ],
  },
  {
    name: 'favoriteMovie',
    label: 'Favorite Movie',
    operators: [{ name: '=', label: 'is' }],
  },
];

const defaultQuery: RuleGroupType = {
  combinator: 'and',
  rules: [
    { field: 'name', operator: 'beginsWith', value: 'Stev' },
    { field: 'birthday', operator: '<', value: '1970-01-01' },
    { field: 'guitars', operator: '>', value: 5 },
    { field: 'favoriteMovie', operator: '=', value: 'Crossroads (1986)' },
  ],
};

export default () => <QueryBuilder fields={fields} defaultQuery={defaultQuery} />;
```

</SandpackRQB>

## `getOperators` prop

While the field `operators` property works well for individual field customizations, the `getOperators` function prop centralizes all operator logic in one location.

`getOperators` receives two arguments: the field identifier and a meta object containing the complete field definition. Using this information, you can reference the `fields` array (or other data sources) to return appropriate operator lists with custom names and labels.

This example demonstrates custom field properties for operator management. Each field includes a custom `datatype` property that determines operator selection and labeling. The `defaultOperators` export provides base functionality where needed. Note that when present, a field's `operators` property overrides `getOperators` results—observe how "Favorite Movie" shows only the "is" operator despite having `datatype: "text"`.

<SandpackRQB rqbVersion={7} options={{ editorHeight: 444 }}>

```tsx
import { defaultOperators, Field, QueryBuilder, RuleGroupType } from 'react-querybuilder';
import 'react-querybuilder/dist/query-builder.css';

const fields: Field[] = [
  { name: 'name', label: 'Name', datatype: 'text' },
  { name: 'birthday', label: 'Birthday', datatype: 'date', inputType: 'date' },
  { name: 'guitars', label: 'Guitars', datatype: 'number', inputType: 'number' },
  {
    name: 'favoriteMovie',
    label: 'Favorite Movie',
    datatype: 'text',
    operators: [{ name: '=', label: 'is' }],
  },
];

const getOperators = (fieldName: string, { fieldData }: { fieldData: Field }) => {
  switch (fieldData.datatype) {
    case 'text':
      return [
        { name: '=', label: 'is' },
        { name: '!=', label: 'is not' },
        ...defaultOperators.filter(op =>
          [
            'contains',
            'beginsWith',
            'endsWith',
            'doesNotContain',
            'doesNotBeginWith',
            'doesNotEndWith',
            'null',
            'notNull',
            'in',
            'notIn',
          ].includes(op.name)
        ),
      ];
    case 'number':
      return [
        ...defaultOperators.filter(op => ['=', '!='].includes(op.name)),
        { name: '<', label: 'less than' },
        { name: '<=', label: 'less than or equal to' },
        { name: '>', label: 'greater than' },
        { name: '>=', label: 'greater than or equal to' },
        ...defaultOperators.filter(op => ['null', 'notNull'].includes(op.name)),
      ];
    case 'date':
      return [
        { name: '=', label: 'on' },
        { name: '!=', label: 'not on' },
        { name: '<', label: 'before' },
        { name: '<=', label: 'on or before' },
        { name: '>', label: 'after' },
        { name: '>=', label: 'on or after' },
        ...defaultOperators.filter(op => ['null', 'notNull'].includes(op.name)),
      ];
  }
  return defaultOperators;
};

const defaultQuery: RuleGroupType = {
  combinator: 'and',
  rules: [
    { field: 'name', operator: 'beginsWith', value: 'Stev' },
    { field: 'birthday', operator: '<', value: '1970-01-01' },
    { field: 'guitars', operator: '>', value: 5 },
    { field: 'favoriteMovie', operator: '=', value: 'Crossroads (1986)' },
  ],
};

export default () => (
  <QueryBuilder fields={fields} defaultQuery={defaultQuery} getOperators={getOperators} />
);
```

</SandpackRQB>
